//! In-memory entity state structures.

use craftdig_math::{Vec3f, AABB};

#[derive(Clone, Debug)]
pub struct EntityState {
    /// Dummy entity name that we use for something.
    name: String,

    /// Entity position.
    position: Vec3f,

    /// Collision box in local space.
    collider: AABB,

    /// Physics component.
    // TODO make this more general
    phys: Option<PhysicsComponent>,
}

impl EntityState {
    /// Creates a new bare instance without much.
    pub fn new_bare(name: String) -> Self {
        Self {
            name,
            position: Vec3f::zero(),
            collider: AABB::new_origin(Vec3f::zero()),
            phys: None,
        }
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn position(&self) -> Vec3f {
        self.position
    }

    pub fn set_position(&mut self, pos: Vec3f) {
        self.position = pos;
    }

    pub fn collider(&self) -> &AABB {
        &self.collider
    }

    pub fn set_collider(&mut self, col: AABB) {
        self.collider = col;
    }

    pub fn phys(&self) -> Option<&PhysicsComponent> {
        self.phys.as_ref()
    }

    pub fn phys_mut(&mut self) -> &mut Option<PhysicsComponent> {
        &mut self.phys
    }
}

#[derive(Clone, Debug)]
pub struct PhysicsComponent {
    /// Velocity vector, added to position every tick, adjusted for tick duration.
    velocity: Vec3f,

    /// If the entity should obey gravity.
    obey_gravity: bool,

    /// If we should apply gravity and try to move the entity down.
    is_grounded: bool,
}

impl PhysicsComponent {
    /// Creates a new still instance.
    pub fn new_still(is_grounded: bool) -> Self {
        Self {
            velocity: Vec3f::zero(),
            obey_gravity: true,
            is_grounded,
        }
    }

    pub fn velocity(&self) -> Vec3f {
        self.velocity
    }

    pub fn set_velocity(&mut self, vel: Vec3f) {
        self.velocity = vel;
    }

    pub fn obey_gravity(&self) -> bool {
        self.obey_gravity
    }

    pub fn set_obey_gravity(&mut self, obey_gravity: bool) {
        self.obey_gravity = obey_gravity;
    }

    pub fn is_grounded(&self) -> bool {
        self.is_grounded
    }

    pub fn set_grounded(&mut self, g: bool) {
        self.is_grounded = g;
    }
}
